﻿using CyUSB;
using EDF;
using EEG_NIRS_Record.Properties;
using MathNet.Numerics.IntegralTransforms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using ZedGraph;

namespace EEG_NIRS_Record
{
    public partial class MainForm : Form
    {
        [DllImport("EdfReaderAndWriter.dll")]
        public static extern int WriteEdf_File(string filename, int number_of_signals, int number_of_each_data_record);

        [DllImport("EdfReaderAndWriter.dll")]
        public static extern unsafe int WriteEdf_WriteData(double* data);

        [DllImport("EdfReaderAndWriter.dll")]
        public static extern int WriteEdf_Finish();


        TabPage tabpage_eeg;
        TabPage tabpage_nirs;
        // 设置窗口公开
        public Configuration configuration;
        EEGForm eegform;
        NIRSForm nirsform;

        // 设置脑电极位置的窗口
        TopoForm eegtopoform;
        TopoForm nirstopoform;
        public ChannelForm channelform;
        CyUSBDevice myDevice;
        USBDeviceList usbDevices;
        CyUSBEndPoint send_EndPoint;
        CyUSBEndPoint receive_EndPoint;
        bool bRunning = false;
        bool bReady = false;
        Graphics g;
        Bitmap image;
        Pen black_pen;
        Pen blue_pen;
        SolidBrush white_brush;
        Font font;
        public int where_eeg;
        public int where_nirs;
        int showtype;

        int[,] buf_data;
        double[] old;
        public double[] eeg_data_for_topo;
        public double[] nirs_data_for_topo;
        public List<int> index_of_show = new List<int>();
        int num_of_eeg;
        int num_of_nirs;
        int x = 0;
        int eeg_zoom = 50;
        Rectangle rc = new Rectangle();

        OpticsProcess[] op;
        int fs = 1000;
        double[] fc1;
        double[] fc2;

        EDFFile eeg_edf, nirs_edf;
        EDFDataRecord eeg_record = new EDFDataRecord();
        EDFDataRecord nirs_record = new EDFDataRecord();
        string startup_path, data_path;
        string eeg_file, nirs_file;

        ZedGraphControl zed;

        // 绘制图形委托
        delegate void DrawEEG_EventHandler(int[,] data, int len);
        delegate void DrawNIRS_EventHandler(Hbr[] hbr);
        // 更新委托
        delegate void UpdateEEG_EventHandler();
        delegate void UpdateNIRS_EventHandler();

        public MainForm()
        {
            //FileStream fss = new FileStream("shit.txt", FileMode.Create);
            //StreamWriter sww = new StreamWriter(fss);  
            //Complex[] samples = new Complex[5000];
            //double[] data = new double[5000];
            //for (int i = 0; i < 5000; i++)
            //{
            //    samples[i] = new Complex(Math.Sin(2*Math.PI*10*i/1000), 0);
            //    data[i] = Math.Sin(2 * Math.PI * 10 * i / 1000);
            //}
            //Fourier.Forward(samples, FourierOptions.Matlab);

            //double[] power = new double[5000];
            //for (int i = 0; i < 5000; i++)
            //{
            //    power[i] = Complex.Abs(samples[i]);
            //}
            //for (int i = 0; i < 5000; i++)
            //{
            //    sww.WriteLine(data[i] + "\t" + power[i]);
            //}
            //sww.Close();
            //fss.Close();

            InitializeComponent();

            ShowBackground(true);
            configuration = new Configuration();

            usbDevices = new USBDeviceList(CyConst.DEVICES_CYUSB);
            usbDevices.DeviceAttached += new EventHandler(usbDevices_DeviceAttached);
            usbDevices.DeviceRemoved += new EventHandler(usbDevices_DeviceRemoved);
            myDevice = usbDevices[0x04B4, 0x1004] as CyUSBDevice;
            //if (myDevice == null)
            //{
            //    MessageBox.Show("Please connect the device !", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            //    Environment.Exit(0);
            //}
            receive_EndPoint = myDevice.EndPointOf(0x86);//dll里的类
            send_EndPoint = myDevice.EndPointOf(0x82);

            image = new Bitmap(pb_eeg.Width, pb_eeg.Height);
            pb_eeg.Image = image;
            g = Graphics.FromImage(image);            


            black_pen = new Pen(Color.Black, 1);
            blue_pen = new Pen(Color.Blue, 1);
            white_brush = new SolidBrush(Color.White);
            font = new Font("宋体", 9, FontStyle.Bold);

            where_eeg = 0;
            where_nirs = 0;
            showtype = -1;

            fc1 = new double[16];
            fc2 = new double[16];
            for (int i = 0; i < 16; i++)
            {
                fc1[i] = 100 + 30 * i;
                fc2[i] = 100 + 30 * i;
            }

            startup_path = Application.StartupPath;
            data_path = startup_path + "\\Data";
            if (!Directory.Exists(data_path))
            {
                Directory.CreateDirectory(data_path);
            }
            trackBar.TrackBar.Maximum = 999;
            trackBar.TrackBar.Minimum = 0;
            trackBar.TrackBar.Value = 500;            
        }
        private void ShowBackground(bool bshown)
        {
            if (bshown)
            {
                this.BackgroundImage = Resources.brain;
                tabControl1.Visible = false;
            }
            else
            {
                this.BackgroundImage = null;
                tabControl1.Visible = true;
            }
        }
        private void InitTabPage(int showtype)
        {
            tabControl1.Controls.Clear();
            switch (showtype)
            {
                case 0:
                    tabControl1.Controls.Add(this.tp_eeg);
                    break;
                case 1:
                    Init_NIRS_Layout(tableLayoutPanel, configuration.label_nirs_list.Count);
                    tabControl1.Controls.Add(this.tp_nirs);
                    break;
                case 2:
                    tabControl1.Controls.Add(this.tp_eeg);
                    Init_NIRS_Layout(tableLayoutPanel, configuration.label_nirs_list.Count);
                    tabControl1.Controls.Add(this.tp_nirs);
                    break;
            }
        }
        private void Init_NIRS_Layout(TableLayoutPanel tableLayoutPanel, int ch)
        {
            SetRowColumn(tableLayoutPanel, ch);
            tableLayoutPanel.CellBorderStyle = TableLayoutPanelCellBorderStyle.None;

            for (int i = 0; i < tableLayoutPanel.RowCount; i++)
            {
                tableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
            }
            for (int i = 0; i < tableLayoutPanel.ColumnCount; i++)
            {
                tableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
            }

            LineItem lineitem;
            Color red = Color.Red;
            Color green = Color.Green;
            int ii = 0;
            int jj = 0;
            for (int i = 0; i < ch; i++)
            {
                RollingPointPairList list1_hbo = new RollingPointPairList(300);
                RollingPointPairList list1_hb = new RollingPointPairList(300);
                zed = new ZedGraphControl();
                zed.Dock = DockStyle.Fill;
                zed.Margin = new Padding(0);
                GraphPane myPane = zed.GraphPane;
                myPane.Border.IsVisible = false;
                myPane.Legend.FontSpec.Size = 10F;
                myPane.Title.Text = "CH" + (i + 1).ToString();
                myPane.XAxis.Title.Text = "";
                myPane.YAxis.Title.Text = "HR";
                myPane.XAxis.Type = AxisType.Date;
                myPane.XAxis.Scale.Format = "HH:mm:ss";
                myPane.YAxis.Title.FontSpec.Size = 10F;
                myPane.XAxis.Scale.FontSpec.Size = 10F;
                myPane.YAxis.Scale.FontSpec.Size = 10F;
                //myPane.YAxis.Scale.Max = 0.5;
                //myPane.YAxis.Scale.Min = -0.5;
                myPane.XAxis.MajorGrid.IsVisible = true;
                myPane.YAxis.MajorGrid.IsVisible = true;
                myPane.XAxis.MajorGrid.Color = Color.Gray;
                myPane.YAxis.MajorGrid.Color = Color.Gray;
                string str = "HbO";
                lineitem = myPane.AddCurve(str, list1_hbo, red, SymbolType.None);
                lineitem.Line.Width = 2.0F;
                str = "Hb";
                lineitem = myPane.AddCurve(str, list1_hb, green, SymbolType.None);
                lineitem.Line.Width = 2.0F;
                tableLayoutPanel.Controls.Add(zed, jj, ii);
                jj++;  // 控制zed分布
                if (jj == tableLayoutPanel.ColumnCount)
                {
                    jj = 0;
                    ii++;
                }

            }
        }
        private void SetRowColumn(TableLayoutPanel tableLayoutPanel, int row, int column)
        {
            tableLayoutPanel.Controls.Clear();
            tableLayoutPanel.RowCount = row;
            tableLayoutPanel.ColumnCount = column;
        }
        private void SetRowColumn(TableLayoutPanel tableLayoutPanel, int ch)
        {
            if (ch == 1)
            {
                SetRowColumn(tableLayoutPanel, 1, 1);
            }
            else if (ch == 2)
            {
                SetRowColumn(tableLayoutPanel, 2, 1);
            }
            else if (ch <= 4)
            {
                SetRowColumn(tableLayoutPanel, 2, 2);
            }
            else if (ch <= 6)
            {
                SetRowColumn(tableLayoutPanel, 3, 2);
            }
            else if (ch <= 9)
            {
                SetRowColumn(tableLayoutPanel, 3, 3);
            }
            else if (ch <= 12)
            {
                SetRowColumn(tableLayoutPanel, 3, 4);
            }
            else if (ch <= 16)
            {
                SetRowColumn(tableLayoutPanel, 4, 4);
            }
            else if (ch <= 20)
            {
                SetRowColumn(tableLayoutPanel, 4, 5);
            }
            else if (ch <= 25)
            {
                SetRowColumn(tableLayoutPanel, 5, 5);
            }
            else if (ch <= 30)
            {
                SetRowColumn(tableLayoutPanel, 5, 6);
            }
            else if (ch <= 36)
            {
                SetRowColumn(tableLayoutPanel, 6, 6);
            }
            else if (ch <= 42)
            {
                SetRowColumn(tableLayoutPanel, 6, 7);
            }
            else if (ch <= 49)
            {
                SetRowColumn(tableLayoutPanel, 7, 7);
            }
            else
            {
                SetRowColumn(tableLayoutPanel, 8, 8);
            }
        }
        private void usbDevices_DeviceRemoved(object sender, EventArgs e)
        {

        }
        private void usbDevices_DeviceAttached(object sender, EventArgs e)
        {

        }
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (bRunning == true)
            {
                MessageBox.Show("Please stop the recording first !", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            if (usbDevices != null)
            {
                usbDevices.Dispose();
            }
            if (myDevice != null)
            {
                myDevice.Dispose();
            }
        }

        private void btn_configuration_Click(object sender, EventArgs e)
        {
            if (configuration.ShowDialog() == DialogResult.OK)
            {
                // 根据EEG和NIRS的注册结果，添加tabpage
                showtype = configuration.ShowType;
                InitTabPage(configuration.ShowType);
                ShowBackground(false);
                if (showtype == 0)
                {
                    bReady = true;
                }

                num_of_eeg = configuration.label_eeg_list.Count;
                buf_data = new int[1000 * 8, num_of_eeg];
                old = new double[num_of_eeg];
                eeg_data_for_topo = new double[num_of_eeg];
                channelform = new ChannelForm(this);
                for (int i = 0; i < num_of_eeg; i++)
                {
                    index_of_show.Add(i);
                }
                panel_ch.Invalidate(); // 画通道label

                num_of_nirs = configuration.nirs_list.Count;
                nirs_data_for_topo = new double[num_of_nirs];
                op = new OpticsProcess[num_of_nirs];
                for (int i = 0; i < num_of_nirs; i++)
                {
                    int source_index = configuration.index_ch_source_list[i];   // 根据每个通道对应的source，得到两个调制频率 fc1，fc2
                    op[i] = new OpticsProcess(fs, fc1[source_index], fc2[source_index]);
                }



                if (!Directory.Exists(data_path + "\\" + configuration.tb_id.Text))
                {
                    Directory.CreateDirectory(data_path + "\\" + configuration.tb_id.Text);
                }
                eeg_file = data_path + "\\" + configuration.tb_id.Text + "\\EEG_" + DateTime.Now.Year + DateTime.Now.Month.ToString("D2") + DateTime.Now.Day.ToString("D2") + "_" + DateTime.Now.Hour.ToString("D2") + DateTime.Now.Minute.ToString("D2") + DateTime.Now.Second.ToString("D2") + ".edf";
                nirs_file = data_path + "\\" + configuration.tb_id.Text + "\\NIRS_" + DateTime.Now.Year + DateTime.Now.Month.ToString("D2") + DateTime.Now.Day.ToString("D2") + "_" + DateTime.Now.Hour.ToString("D2") + DateTime.Now.Minute.ToString("D2") + DateTime.Now.Second.ToString("D2") + ".edf";
                init_edf(showtype);
            }
        }
        private void init_edf(int showtype)
        {
            switch (showtype)
            {
                case 0:
                    unsafe
                    {
                        WriteEdf_File(eeg_file, num_of_eeg, 1000);
                    }
                    //init_eeg_edf();
                    break;
                case 1:
                    init_nirs_edf();
                    break;
                case 2:
                    init_eeg_edf();
                    init_nirs_edf();
                    break;
            }
        }
        List<EDFSignal> eeg_signal_list = new List<EDFSignal>();
        private void init_eeg_edf()
        {
            eeg_edf = new EDFFile();
            eeg_edf.Header.Version = "0";//has to be 0
            eeg_edf.Header.StartDateTime = DateTime.Now;//the pecise time the record is recorded
            eeg_edf.Header.NumberOfSignalsInDataRecord = num_of_eeg;
            eeg_edf.Header.DurationOfDataRecordInSeconds = 1;// duration of each datarecord in SECOND 

            for (int i = 0; i < eeg_edf.Header.NumberOfSignalsInDataRecord; i++)
            {
                EDFSignal signal = new EDFSignal();
                signal.Label = "signal_" + i;
                signal.IndexNumber = i;//the index of the signal in each daterecord;becasue of same names of signals in datarecord the the object signal.IndexNumberWithLabel become the unique key to identify the signals;
                signal.DigitalMaximum = 32767;
                signal.PhysicalMaximum = 97;
                signal.DigitalMinimum = -32768;
                signal.PhysicalMinimum = -97;
                signal.TransducerType = "name_of_device";
                signal.PhysicalDimension = "mV";
                signal.NumberOfSamplesPerDataRecord = 1000;
                eeg_signal_list.Add(signal);
            }
            eeg_edf.Header.Signals = eeg_signal_list;

            EDFLocalPatientIdentification patient_information = new EDFLocalPatientIdentification("patientCode", "M", DateTime.Parse("1993/04/26"), "nameOfPatient");
            eeg_edf.Header.PatientIdentification = patient_information;

            EDFLocalRecordingIdentification record_information = new EDFLocalRecordingIdentification(DateTime.Now.ToString(), "recordCode", "technician", "equipmentName");
            eeg_edf.Header.RecordingIdentification = record_information;

            eeg_edf.saveFile(eeg_file);
        }
        //private void init_eeg_edf(int num_ch)
        //{

        //}
        List<EDFSignal> nirs_signal_list = new List<EDFSignal>();
        private void init_nirs_edf()
        {
            nirs_edf = new EDFFile();
            nirs_edf.Header.Version = "0";//has to be 0
            nirs_edf.Header.StartDateTime = DateTime.Now;//the pecise time the record is recorded
            nirs_edf.Header.NumberOfSignalsInDataRecord = num_of_nirs * 2;
            nirs_edf.Header.DurationOfDataRecordInSeconds = 1;// duration of each datarecord in SECOND 

            for (int i = 0; i < nirs_edf.Header.NumberOfSignalsInDataRecord; i++)
            {
                EDFSignal signal = new EDFSignal();
                signal.Label = "signal_" + i;
                signal.IndexNumber = i;//the index of the signal in each daterecord;becasue of same names of signals in datarecord the the object signal.IndexNumberWithLabel become the unique key to identify the signals;
                signal.DigitalMaximum = 32767;
                signal.PhysicalMaximum = 97;
                signal.DigitalMinimum = -32768;
                signal.PhysicalMinimum = -97;
                signal.TransducerType = "name_of_device";
                signal.PhysicalDimension = "mV";
                signal.NumberOfSamplesPerDataRecord = 10;
                nirs_signal_list.Add(signal);
            }
            nirs_edf.Header.Signals = nirs_signal_list;

            EDFLocalPatientIdentification patient_information = new EDFLocalPatientIdentification("patientCode", "M", DateTime.Parse("1993/04/26"), "nameOfPatient");
            nirs_edf.Header.PatientIdentification = patient_information;

            EDFLocalRecordingIdentification record_information = new EDFLocalRecordingIdentification(DateTime.Now.ToString(), "recordCode", "technician", "equipmentName");
            nirs_edf.Header.RecordingIdentification = record_information;

            nirs_edf.saveFile(nirs_file);
        }

        Queue<byte> queue = new Queue<byte>();
        private void ReceiveDate()
        {
            byte[] receive_data = new byte[512];
            int buf_len = 512;
            bool bRecieved = false;

            while (bRunning)
            {
                try
                {
                    bRecieved = receive_EndPoint.XferData(ref receive_data, ref buf_len);
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.ToString());
                }
                if (bRecieved == true)
                {
                    Monitor.Enter(queue);
                    for (int i = 0; i < buf_len; i++)
                    {
                        queue.Enqueue(receive_data[i]);
                    }
                    Monitor.Exit(queue);

                }

            }
        }
        int length;
        private void EEG_DataProcess()
        {
            int[,] data = new int[1000 * 8, num_of_eeg];
            double[] edf_data = new double[num_of_eeg];
            byte[] tempdata = null;
            List<byte> m = new List<byte>();
            byte temp;
            int step = 0;
            byte test = 0;
            int num = 0;
            int num_of_byte = 0;
            byte[] tdata = new byte[2 * num_of_eeg];
            FileStream a;
            //StreamWriter sw = new StreamWriter(a);
            while (bRunning)
            {
                if (queue.Count == 0)
                {
                    continue;
                }
                Monitor.Enter(queue);
                //tempdata = queue.ToArray();
                m.AddRange(queue.ToArray());
                queue.Clear();
                Monitor.Exit(queue);
                // 查看读到的数据，
                if (File.Exists(@"C:\Users\CL\Desktop\file1.txt"))
                {
                    a = new FileStream(@"C:\Users\CL\Desktop\file1.txt", FileMode.Append);
                }
                else
                {
                     a= new FileStream(@"C:\Users\CL\Desktop\file1.txt", FileMode.Create);

                }
                StreamWriter sw = new StreamWriter(a);
                sw.WriteLine(BitConverter.ToString(m.ToArray(),0));
                m.Clear();
                sw.Close();
                a.Close();
                bReady = true;
                if (bReady == true)
                {
                    length = 0;


                    //for (int i = 0; i < tempdata.Length; i++)
                    //{
                    //    temp = tempdata[i];
                    //    switch (step)
                    //    {
                    //        case 0:
                    //            //     if (temp == 0x55)
                    //            //     {
                    //            test += temp;
                    //            step = 1;
                    //            //    }
                    //            break;
                    //        case 1:
                    //            //      if (temp == 0x00)
                    //            ///       {
                    //            test += temp;
                    //            step = 2;
                    //            //      }
                    //            //  else
                    //            //    {
                    //            //          test = 0;
                    //            //         step = 0;
                    //            //         Console.WriteLine("case 1 error!");
                    //            //     }
                    //            break;
                    //        case 2:
                    //            /* if (temp == 0x01 || temp == 0x02 || temp == 0x03)
                    //             { */
                    //            test += temp;
                    //            step = 3;
                    //            /*    }
                    //                else
                    //                {
                    //                    test = 0;
                    //                    step = 0;
                    //                    Console.WriteLine("case 2 error!");
                    //                }*/
                    //            break;
                    //        case 3:
                    //            test += temp;
                    //            num_of_byte = temp;
                    //            /*      if (num_of_byte != num_of_eeg * 2)
                    //                  {
                    //                      string exception = "出现配置的通道数与实际数据不符的异常：\r\nnum_of_eeg:" + num_of_eeg + "\r\nnum_of_byte:" + num_of_byte;
                    //                      step = 0;
                    //                      test = 0;
                    //                      Console.WriteLine(exception);
                    //                      //MessageBox.Show(exception);
                    //                      break;
                    //                  }*/
                    //            step = 4;
                    //            break;
                    //        case 4:
                    //            test += temp;
                    //            tdata[num] = temp;
                    //            num++;
                    //            /*   if (num == num_of_byte)
                    //                {*/
                    //            step = 5;
                    //            //}
                    //            break;
                    //        case 5:
                    //            step = 0;
                    //            num = 0;
                    //            /*      if (temp != test)
                    //                  {
                    //                      string exception = "校验异常：\ttest: 0x" + test.ToString("X2") + "\ttemp: 0x" + temp.ToString("X2");
                    //                      Console.WriteLine(exception);
                    //                      test = 0;
                    //                      break;
                    //                  }*/
                    //            for (int j = 0; j < num_of_eeg; j++)
                    //            {
                    //                data[length, j] = tdata[2 * j] + (short)(tdata[2 * j + 1] * 256);
                    //                //buf_data[len, j] = ((tdata[2 * j] + tdata[2 * j + 1] * 256)<<16)/65536; 
                    //                edf_data[j] = data[length, j];
                    //            }

                    //            length++;
                    //            if (length == 8 * 1000)
                    //            {
                    //                //   length = 0;
                    //                Console.WriteLine("data缓冲区溢出！");
                    //            }
                    //            unsafe
                    //            {
                    //                fixed (double* p = edf_data)
                    //                {
                    //                    WriteEdf_WriteData(p);
                    //                }
                    //            }
                    //            test = 0;
                    //            break;
                    //    }
                    //}
                    //switch (where_eeg)
                    //{
                    //    case 0:
                    //        //DrawEEG(data, 1);

                    //        this.BeginInvoke(new DrawEEG_EventHandler(DrawEEG), data, length);
                    //        break;
                    //    case 1:
                    //        //eegform.BeginInvoke(new DrawEEG_EventHandler(eegform.DrawEEG), data, length);
                    //        break;
                    //}
                }
            }
            unsafe
            {
                WriteEdf_Finish();
            }
        }

        private void DrawEEG(int[,] data, int len)
        {
            if (x >= pb_eeg.Width - 1)
            {
                x = 0;
            }
            g.FillRectangle(white_brush, x + 1, 0, len + 1, pb_eeg.Height);
            rc.X = x - 10;
            for (int i = 0; i < len; i++)
            {
                lock (index_of_show)
                {
                    int num_of_show = index_of_show.Count;
                    for (int j = 0; j < num_of_show; j++)
                    {
                        g.DrawLine(blue_pen, x, (int)(pb_eeg.Height * (j + 1) / (num_of_show + 1) - (int)old[index_of_show[j]] / eeg_zoom), x + 1, (int)(pb_eeg.Height * (j + 1) / (num_of_show + 1) - data[i, index_of_show[j]] / eeg_zoom));
                        //old[index_of_show[j]] = data[i, index_of_show[j]];
                    }
                }
                for (int j = 0; j < num_of_eeg; j++)
                {
                    old[j] = data[i, j];
                }
                x++;
            }
            // 赋值画topo的数据
            //
            lock (eeg_data_for_topo)
            {
                eeg_data_for_topo = old.ToArray();
            }
            //for (int i = 0; i < num_of_eeg; i++)
            //{
            //    eeg_data_for_topo[i] = old[i];
            //}

            g.DrawLine(black_pen, x + 1, 0, x + 1, pb_eeg.Height);

            rc.Y = 0;
            rc.Width = len + 2 + 30;
            rc.Height = pb_eeg.Height;
            pb_eeg.Invalidate(rc);
        }

        private void NIRS_DataProcess()
        {
            bool baseline_got = false; // 是否得到baseline
            double[][] light = new double[num_of_nirs][];
            double[][] mean = new double[num_of_nirs][];
            double[][] baseline = new double[num_of_nirs][];
            Hbr[] hbr = new Hbr[num_of_nirs];
            for (int i = 0; i < num_of_nirs; i++)
            {
                light[i] = new double[2];
                mean[i] = new double[2];
                baseline[i] = new double[2];
                hbr[i] = new Hbr();
            }
            int[,] data = null;
            int data_len = 0;
            while (bRunning)
            {
                //lock (buf_data)
                //{
                //    data = (int[,])buf_data.Clone();
                //    data_len = len;
                //    len = 0;
                //}
                if (data_len == 0)
                {
                    continue;
                }
                for (int i = 0; i < data_len; i++)
                {
                    for (int j = 0; j < num_of_nirs; j++)
                    {
                        int detector_index = configuration.index_ch_detector_list[j]; // 解调每个通道对应的detector的数据
                        try
                        {
                            light[j] = op[j].Demodulate(data[i, detector_index]);
                        }
                        catch (IndexOutOfRangeException e)
                        {
                            Console.WriteLine("num_of_nirs:" + num_of_nirs);
                            Console.WriteLine("detector_index:" + detector_index);
                            Console.WriteLine("j:" + j);
                            Console.WriteLine("num of op:" + op.Count());
                            Console.WriteLine("light:" + light.GetLength(0));
                            FileStream fs = new FileStream("error_log.txt", FileMode.Create);
                            StreamWriter sw = new StreamWriter(fs);
                            sw.WriteLine("num_of_nirs:" + num_of_nirs);
                            sw.WriteLine("detector_index:" + detector_index);
                            sw.WriteLine("j:" + j);
                            sw.WriteLine("num of op:" + op.Count());
                            sw.WriteLine("light:" + light.GetLength(0));
                            sw.Close();
                            fs.Close();
                            MessageBox.Show(e.Data.ToString());
                        }

                    }
                    if (baseline_got == false)
                    {
                        if (op[0].counter >= (2 * fs))  // 前2秒数据不算在基线
                        {
                            for (int j = 0; j < num_of_nirs; j++)
                            {
                                mean[j][0] += light[j][0];
                                mean[j][1] += light[j][1];
                            }

                        }
                        if (op[0].counter % (0.1 * fs) != 0)
                        {
                            tabControl1.BeginInvoke(new MethodInvoker(delegate { tabControl1.CreateGraphics().FillRectangle(Brushes.LightBlue, tabControl1.Width * op[0].counter / (10 * fs), 0, tabControl1.Width / 10, tabControl1.ItemSize.Height); })); // 初始化
                        }
                        if (op[0].counter == (10 * fs))
                        {
                            for (int j = 0; j < num_of_nirs; j++)
                            {
                                baseline[j][0] = mean[j][0] / 8 * fs;
                                baseline[j][1] = mean[j][1] / 8 * fs;
                                mean[j][0] = 0;
                                mean[j][1] = 0;
                            }
                            tabControl1.BeginInvoke(new MethodInvoker(delegate { tabControl1.Invalidate(); })); // 初始化
                            baseline_got = true;
                            bReady = true;
                        }
                        continue;
                    }
                    for (int j = 0; j < num_of_nirs; j++)
                    {
                        mean[j][0] += light[j][0];
                        mean[j][1] += light[j][1];
                    }

                    if (op[0].counter % (0.1 * fs) != 0)
                    {
                        continue;
                    }
                    for (int j = 0; j < num_of_nirs; j++)
                    {
                        mean[j][0] /= (0.1 * fs);
                        mean[j][1] /= (0.1 * fs);

                        hbr[j] = op[j].mes2hb(mean[j], baseline[j]);
                        nirs_data_for_topo[j] = hbr[j].hbo;  // 有点漏洞：可能数据跟新到一半就显示了

                        mean[j][0] = 0;
                        mean[j][1] = 0;
                    }
                    switch (where_nirs)
                    {
                        case 0:
                            DrawNIRS(hbr);
                            break;
                        case 1:
                            nirsform.DrawNIRS(hbr);  // 奇怪！！！ 为什么不必用委托？
                            //nirsform.BeginInvoke(new DrawNIRS_EventHandler(nirsform.DrawNIRS), hbr);     // 错！！！                    
                            break;
                    }
                }

            }
        }
        private void DrawNIRS(Hbr[] hbr)
        {
            DateTime currentTime = DateTime.Now;
            double time = (double)new XDate(currentTime);
            int i = 0;
            foreach (ZedGraphControl zed in tableLayoutPanel.Controls)
            {
                IPointListEdit list1 = zed.GraphPane.CurveList[0].Points as IPointListEdit;
                list1.Add(time, hbr[i].hbo);
                list1 = zed.GraphPane.CurveList[1].Points as IPointListEdit;
                list1.Add(time, hbr[i].hb);
                i++;
                try
                {
                    this.BeginInvoke(new MethodInvoker(delegate { zed.AxisChange(); zed.Refresh(); }));
                }
                catch (Exception e)
                {
                    MessageBox.Show(e.ToString());
                }
            }
        }
        private void btn_start_Click(object sender, EventArgs e)
        {
            if (showtype == -1)
            {
                MessageBox.Show("Please add configuration information !", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
            bRunning = true;
            Thread ReceiveThread = new Thread(new ThreadStart(ReceiveDate));
            ReceiveThread.IsBackground = true;
            ReceiveThread.Name = "ReceiveThread";
            ReceiveThread.Start();
            ////
            Thread EEG_DataProcessThread;
            Thread NIRS_DataProcessThread;
            switch (showtype)
            {
                case 0:
                    EEG_DataProcessThread = new Thread(new ThreadStart(EEG_DataProcess));
                    EEG_DataProcessThread.IsBackground = true;
                    EEG_DataProcessThread.Name = "EEG_DataProcessThread";
                    EEG_DataProcessThread.Start();
                    break;
                case 1:
                    NIRS_DataProcessThread = new Thread(new ThreadStart(NIRS_DataProcess));
                    NIRS_DataProcessThread.IsBackground = true;
                    NIRS_DataProcessThread.Name = "NIRS_DataProcessThread";
                    NIRS_DataProcessThread.Start();
                    break;
                case 2:
                    EEG_DataProcessThread = new Thread(new ThreadStart(EEG_DataProcess));
                    EEG_DataProcessThread.IsBackground = true;
                    EEG_DataProcessThread.Name = "EEG_DataProcessThread";
                    EEG_DataProcessThread.Start();
                    /////
                    NIRS_DataProcessThread = new Thread(new ThreadStart(NIRS_DataProcess));
                    NIRS_DataProcessThread.IsBackground = true;
                    NIRS_DataProcessThread.Name = "NIRS_DataProcessThread";
                    NIRS_DataProcessThread.Start();
                    break;
                case -1:
                    break;
            }


            byte[] cmd_start = new byte[5];
            cmd_start[0] = 0x55;
            cmd_start[1] = 0x00;
            cmd_start[2] = 0;
            cmd_start[3] = 0x00;
            cmd_start[4] = (byte)(cmd_start[0] + cmd_start[1] + cmd_start[2] + cmd_start[3]);
        }

        private void btn_stop_Click(object sender, EventArgs e)
        {
            bRunning = false;

        }

        private void tabControl1_DoubleClick(object sender, EventArgs e)
        {
            switch (tabControl1.SelectedTab.Text)
            {
                case "EEG":
                    eegform = new EEGForm(this);
                    eegform.Show();
                    tabpage_eeg = tabControl1.SelectedTab;
                    where_eeg = 1;
                    break;
                case "NIRS":
                    nirsform = new NIRSForm(this);
                    nirsform.Show();
                    tabpage_nirs = tabControl1.SelectedTab;
                    where_nirs = 1;
                    break;
            }
            //Thread.Sleep(10);
            tabControl1.Controls.Remove(tabControl1.SelectedTab);
            if (tabControl1.Controls.Count < 1)
            {
                ShowBackground(true);
            }
        }
        public void RecoverTabPage(int type)
        {
            ShowBackground(false);
            switch (type)
            {
                case 0:
                    tabControl1.Controls.Add(tabpage_eeg);
                    tabControl1.SelectedTab = tabpage_eeg;
                    tabpage_eeg = null;
                    break;
                case 1:
                    tabControl1.Controls.Add(tabpage_nirs);
                    tabControl1.SelectedTab = tabpage_nirs;
                    tabpage_nirs = null;
                    break;
            }
        }

        private void pb_eeg_Resize(object sender, EventArgs e)
        {
            image = new Bitmap(pb_eeg.Width, pb_eeg.Height);
            pb_eeg.Image = image;
            g = Graphics.FromImage(image);
        }

        private void btn_eeg_topo_Click(object sender, EventArgs e)
        {
            if (showtype == 1 | showtype == -1)
            {
                return;
            }
            eegtopoform = new TopoForm(this, 0);
            eegtopoform.Text = "EEG TopoGraph";
            eegtopoform.Show();
        }

        private void btn_nirs_topo_Click(object sender, EventArgs e)
        {
            if (showtype == 0 | showtype == -1)
            {
                return;
            }
            nirstopoform = new TopoForm(this, 1);
            nirstopoform.Text = "NIRS TopoGraph";
            nirstopoform.Show();
        }

        private void trackBar_ValueChanged(object sender, EventArgs e)
        {
            eeg_zoom = 1000 - trackBar.TrackBar.Value;
        }

        private void btn_ch_Click(object sender, EventArgs e)
        {
            if (channelform.ShowDialog() == DialogResult.OK)
            {
                panel_ch.Invalidate();
            }
        }

        private void btn_filter_Click(object sender, EventArgs e)
        {

        }

        private void panel_ch_Paint(object sender, PaintEventArgs e)
        {
            Graphics gg = e.Graphics;
            gg.FillRectangle(white_brush, 0, 0, panel_ch.Width, panel_ch.Height);
            for (int i = 0; i < index_of_show.Count; i++)
            {
                gg.DrawString(configuration.label_eeg_list[index_of_show[i]], font, Brushes.Black, 50, panel_ch.Height * (i + 1) / (index_of_show.Count + 1) - 7);
            }
        }

        private void panel_ch_Resize(object sender, EventArgs e)
        {
            panel_ch.Invalidate();
        }

    }
}
